﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
using System.Text.RegularExpressions;
using System.Windows.Forms;
using BlueMarineWindowsFormsClient.ManagerServiceReference;

namespace BlueMarineWindowsFormsClient
{
    public partial class frmEmployeeManager : Form
    {
        private readonly List<TextBox> _ctrl;
        private readonly ManagerServiceClient _employeeManagement;
        private readonly Timer myTimer;

        public frmEmployeeManager()
        {
            InitializeComponent();
            _employeeManagement = new ManagerServiceClient("nettcp1");
            _ctrl = new List<TextBox> {txtName, txtPhone, txtEmail, txtAddress, txtCity, txtCountry};
            cbxJobTitle.SelectedIndex = 0;
            cbxPosition.SelectedIndex = 0;
            myTimer = new Timer {Interval = 100};
            myTimer.Tick += refreshEmpList;
        }

        private void btnNew_Click(object sender, EventArgs e)
        {
            if (btnNew.Text == "New")
            {
                foreach (TextBox textBox in _ctrl)
                {
                    textBox.Clear();
                    textBox.Enabled = true;
                }
                cbxJobTitle.Enabled = true;
                cbxPosition.Enabled = true;
                dtpBirthday.Enabled = true;
                btnCreate.Enabled = true;
                btnUpdate.Enabled = false;
                btnDeactive.Enabled = false;
                btnGetAll.Enabled = true;
                txtUserName.Clear();
                txtPassword.Clear();
                btnNew.Text = "Cancel";
            }
            else
            {
                foreach (TextBox textBox in _ctrl)
                {
                    textBox.Clear();
                    textBox.Enabled = false;
                }
                cbxJobTitle.Enabled = false;
                cbxPosition.Enabled = false;
                txtName.Enabled = false;
                dtpBirthday.Enabled = false;
                btnCreate.Enabled = false;
                btnUpdate.Enabled = false;
                btnDeactive.Enabled = false;
                btnGetAll.Enabled = true;
                btnNew.Text = "New";
            }

            errorProvider.Clear();
        }

        private void btnCreate_Click(object sender, EventArgs e)
        {
            try
            {
                lblStatus.Text = "Writting Employee..";
                if (ValidForm())
                {
                    byte[] image = ImageToByte(ptbEmpImage.Image);
                    string rs = _employeeManagement.EmpAdd(txtName.Text, rdbMale.Checked, dtpBirthday.Value,
                                                           cbxPosition.SelectedItem.ToString(), txtPhone.Text,
                                                           txtEmail.Text, txtAddress.Text, txtCity.Text, txtCountry.Text,
                                                           cbxJobTitle.SelectedItem.ToString(), image);
                    lblStatus.Text = rs == "SUCCESS" ? "SUCCESS: Create Employee" : rs;
                    foreach (TextBox textBox in _ctrl)
                    {
                        textBox.Clear();
                        textBox.Enabled = false;
                    }

                    cbxJobTitle.Enabled = false;
                    cbxPosition.Enabled = false;
                    dtpBirthday.Enabled = false;
                    btnCreate.Enabled = false;
                    btnUpdate.Enabled = false;
                    btnDeactive.Enabled = false;
                    btnGetAll.Enabled = true;
                    btnNew.Text = "New";
                    refresh();
                }
                else
                {
                    lblStatus.Text = "ERROR: Invalid input data";
                }
            }
            catch (Exception ex)
            {
                lblStatus.Text = "ERROR: " + ex.Message;
            }
        }

        private void btnUpdate_Click(object sender, EventArgs e)
        {
            try
            {
                lblStatus.Text = "Updating Employee..";
                byte[] image = ImageToByte(ptbEmpImage.Image);
                string rs = _employeeManagement.EmpModify(int.Parse(txtId.Text), txtName.Text, rdbMale.Checked, dtpBirthday.Value,
                                                          cbxPosition.SelectedText, txtPhone.Text, txtEmail.Text,
                                                          txtAddress.Text, txtCity.Text, txtCountry.Text,
                                                          cbxJobTitle.SelectedText, image);
                lblStatus.Text = rs == "SUCCESS" ? "SUCCESS: Update Employee" : rs;
                btnCreate.Enabled = false;
                btnUpdate.Enabled = false;
                btnDeactive.Enabled = false;
                refresh();
            }
            catch (Exception ex)
            {
                lblStatus.Text = "ERROR: " + ex.Message;
            }
        }

        private void btnDeactive_Click(object sender, EventArgs e)
        {
            try
            {
                string rs = _employeeManagement.EmpDeactive(int.Parse(txtId.Text));
                lblStatus.Text = rs == "SUCCESS" ? "SUCCESS: Deactive Employee" : rs;
                refresh();
            }
            catch (Exception ex)
            {
                lblStatus.Text = "ERROR: " + ex.Message;
            }
        }

        private void btnGetAll_Click(object sender, EventArgs e)
        {
            try
            {
                lblStatus.Text = "Loading List All Employee..";
                List<vEmployeeSubDetail> listEmployee = _employeeManagement.EmpGet(true);
                var bs = new BindingSource {DataSource = listEmployee};
                grdListEmp.DataSource = bs;
                lblStatus.Text = "Load List All Employee Done!";
            }
            catch (Exception ex)
            {
                lblStatus.Text = "ERROR: " + ex.Message;
            }
        }

        private void ptbEmpImage_Click(object sender, EventArgs e)
        {
            try
            {
                var ofd = new OpenFileDialog {Filter = "JPG file|*.jpg|JPEG file|*.jpeg"};
                if (ofd.ShowDialog() == DialogResult.OK)
                {
                    Image img = ResizeImage(Image.FromFile(ofd.FileName));
                    ptbEmpImage.Image = img;
                }
            }
            catch (Exception ex)
            {
                lblStatus.Text = "ERROR: " + ex.Message;
            }
        }

        private void btnSearch_Click(object sender, EventArgs e)
        {
            try
            {
                List<vEmployeeSubDetail> listEmployee = _employeeManagement.EmpSearchByName(txtSearch.Text);
                var bs = new BindingSource {DataSource = listEmployee};
                grdListEmp.DataSource = bs;
            }
            catch (Exception ex)
            {
                lblStatus.Text = "ERROR: " + ex.Message;
            }
        }

        private void grdListEmp_CellClick(object sender, DataGridViewCellEventArgs e)
        {
            try
            {
                if (e.RowIndex < 0) return;
                string employeeID = grdListEmp.Rows[e.RowIndex].Cells["EmployeeID"].Value.ToString();
                Employee employee = _employeeManagement.EmpGetById(int.Parse(employeeID));

                txtId.Text = employee.EmployeeID.ToString();
                txtName.Text = employee.EmployeeName;
                rdbMale.Checked = employee.EmployeeSex;
                dtpBirthday.Value = employee.EmployeeBirthday;
                cbxPosition.SelectedText = employee.EmployeePosition;
                txtPhone.Text = employee.EmployeePhone;
                txtEmail.Text = employee.EmployeeEmail;
                txtAddress.Text = employee.EmployeeAddress;
                txtCity.Text = employee.EmployeeCity;
                txtCountry.Text = employee.EmployeeCountry;
                cbxJobTitle.SelectedText = employee.EmployeeJobTitle;
                txtPassword.Text = employee.EmployeePassword;
                txtUserName.Text = employee.EmployeeAccount;
                ptbEmpImage.Image = ByteToImage(employee.EmployeeImage);

                foreach (TextBox textBox in _ctrl)
                {
                    textBox.Enabled = true;
                }
                cbxJobTitle.Enabled = true;
                cbxPosition.Enabled = true;
                dtpBirthday.Enabled = true;
                btnUpdate.Enabled = true;
                btnDeactive.Enabled = true;
            }
            catch (Exception ex)
            {
                lblStatus.Text = "ERROR: " + ex.Message;
            }
        }

        private void txtEmail_Leave(object sender, EventArgs e)
        {
            string errorMsg;
            ValidEmailAddress(txtEmail.Text, out errorMsg);
            errorProvider.SetError(txtEmail, errorMsg);
        }

        private void txtPhone_Leave(object sender, EventArgs e)
        {
            string errorMsg;
            ValidPhoneNumber(txtPhone.Text, out errorMsg);
            errorProvider.SetError(txtPhone, errorMsg);
        }

        private void textBox_Leave(object sender, EventArgs e)
        {
            ValidString((TextBox) sender);
        }

        private void frmEmployeeManager_Shown(object sender, EventArgs e)
        {
            myTimer.Enabled = true;
        }

        private void refreshEmpList(object sender, EventArgs e)
        {
            refresh();
            myTimer.Dispose();
        }

        private void refresh()
        {
            try
            {
                List<vEmployeeSubDetail> listEmployee = _employeeManagement.EmpGet(false);
                var bs = new BindingSource {DataSource = listEmployee};
                grdListEmp.DataSource = bs;
            }
            catch (Exception ex)
            {
                lblStatus.Text = "ERROR: " + ex.Message;
            }
        }

        private Image ResizeImage(Image img)
        {
            try
            {
                int originalW = img.Width;
                int originalH = img.Height;
                int resizedW = 120;
                int resizedH = 180;
                float per;

                if (originalW <= originalH)
                {
                    per = 120/(float) originalW;
                    resizedH = (int) (originalH*per);
                }
                else
                {
                    per = (float) 180/480;
                    resizedW = (int) (originalW*per);
                }
                var bmp = new Bitmap(resizedW, resizedH);
                Graphics graphic = Graphics.FromImage(bmp);
                graphic.SmoothingMode = SmoothingMode.AntiAlias;
                graphic.InterpolationMode = InterpolationMode.HighQualityBilinear;
                graphic.PixelOffsetMode = PixelOffsetMode.HighQuality;
                graphic.DrawImage(img, 0, 0, resizedW, resizedH);
                graphic.Dispose();
                return bmp;
            }
            catch (Exception ex)
            {
                lblStatus.Text = "ERROR: " + ex.Message;
                return null;
            }
        }

        private byte[] ImageToByte(Image image)
        {
            try
            {
                var ms = new MemoryStream();
                image.Save(ms, ImageFormat.Png);
                return ms.ToArray();
            }
            catch (Exception ex)
            {
                lblStatus.Text = "ERROR: " + ex.Message;
                return null;
            }
        }

        private Image ByteToImage(byte[] data)
        {
            try
            {
                var ms = new MemoryStream(data);
                Image image = Image.FromStream(ms);
                return image;
            }
            catch (Exception ex)
            {
                lblStatus.Text = "ERROR: " + ex.Message;
                return null;
            }
        }

        private bool ValidPhoneNumber(string phoneNumber, out string errorMessage)
        {
            string strPhone = phoneNumber;
            var rePhone = new Regex(@"0+\d{2,3}-\d{3}-\d{4}");
            if (rePhone.IsMatch(strPhone))
            {
                errorMessage = "";
                return true;
            }
            errorMessage = "Phone number mus be valid format. \n" + "0xx[x]-xxx-xxxx";
            return false;
        }

        private bool ValidEmailAddress(string emailAddress, out string errorMessage)
        {
            int idxA = emailAddress.IndexOf("@", StringComparison.Ordinal);
            if (idxA > -1)
            {
                if (
                    emailAddress.IndexOf(".", idxA, StringComparison.Ordinal) > idxA)
                {
                    if (_employeeManagement.EmpEmailCheck(emailAddress))
                    {
                        errorMessage = "";
                        return true;
                    }
                    errorMessage = "Email address is exits";
                    return false;
                }
            }
            errorMessage = "e-mail address must be valid e-mail address format.\n" +
                           "For example 'someone@example.com' ";
            return false;
        }

        private bool ValidString(Control textBox)
        {
            if (textBox.Text.Trim() == "")
            {
                errorProvider.SetError(textBox, "Value is required");
                return false;
            }
            errorProvider.SetError(textBox, "");
            return true;
        }

        private bool ValidForm()
        {
            string err;
            ValidPhoneNumber(txtPhone.Text, out err);
            ValidEmailAddress(txtEmail.Text, out err);
            if (ValidString(txtName) && ValidString(txtAddress) && ValidString(txtCity) && ValidString(txtCountry))
            {
                if (ValidPhoneNumber(txtPhone.Text, out err) && ValidEmailAddress(txtEmail.Text, out err))
                {
                    return true;
                }
            }
            return false;
        }
    }
}